package kgame5.kgu.move {
import kgame5.k3d.core.math.Vector3D;
import kgame5.k3d.core.obj3d.spacial.SpacialVO;
import kgame5.kgu.move.cd.BoxBound2D;
import kgame5.kgu.move.cd.gridcd.GridCollition;

import flash.utils.getTimer;

/*
 * 网格碰撞，这个支持把地图分成大个的网格，每个网格里可以放任意多的任意大小的障碍物。
 * 高级点的游戏要这么用
 * 一个hardVO如果是4个方向，则检测与其他的东西的碰撞
 * 注意这个是个很重要的可用的东西啊
 * !注意这个不支持斜向。斜向不好做
 * 保存障碍物，处理碰撞之类
 * Init()
 * AddBar();
 * RemoveBar();
 * ProcessMove4();
 */
public class MapManager {
	//这个是说找最近的碰撞点，分8份，每次递进一下，检测是否碰到了
	public static const  FIND_HITPOINT_STEPCOUNT:int=4;
	
	//G放到这里不知道是否妥当
	public static const G : int = -3;

	//如果有小人动画的话，则上下左右的动画的顺序
	public static const
		DIR_UP : int = 0,
		DIR_DOWN : int = 1,
		DIR_LEFT : int = 2,
		DIR_RIGHT : int = 3,
		
		DIR_NULL:int=99;//没有选择方向，注意要在128以内哦
	
	//与障碍物碰撞检测.
	//这个是个public是因为gc是需要的删除和检测碰撞表的
	public var gc:GridCollition=new GridCollition();
	
	//地图边界
	private var bound:BoxBound2D=new BoxBound2D();
	
	//绕行器
	private var detour:Detour=new Detour();
	
	public var dur:int;//持续时间，毫秒.这个时间是最坏的时间
	
	//初始化，指定地图边界.barList是hardVO的list
	public function Init(CC:int, RC:int, CellSize:int, barList:Array):void{
		
		gc.Init(CC, RC, CellSize,barList);
		
		bound.left=0;
		bound.up=0;
		bound.right=CC*CellSize;
		bound.down=-RC*CellSize;
	}
	
	//添加障碍物
	public function AddBar(hard:SpacialVO):void{
		this.gc.Add(hard);
	}
	//删除障碍物
	public function RemoveBar(hard:SpacialVO):void{
		this.gc.Remove(hard);
	}
	
	//执行移动,有障碍物，则贴近障碍物，出了边界，则贴紧边界，如果只有一个障碍物，则绕行（注意绕行会改变速度）
	public function ProcessMove4(srcVO:SpacialVO ):void{
		
		var startTime:int=getTimer();//-计算时间
		
		//0，计算一下col.row,有用
		gc.fillColAndRow(srcVO);
		
		//没移动最好了
		var v:Vector3D =srcVO.v3d_v;
		var p:Vector3D =srcVO.v3d_p;
		if(v.x==0&&v.z==0){
			return;
		}
		
		//1，先尝试加到指定位置
		p.add(v);
		
		//2,执行碰撞检测
		//边界碰撞检测
		if(bound.contains(srcVO)==false){//出了边界
			nestToBound(srcVO);//放到边上
			return;
		}
		//物体碰撞检测
		var listObj:Array=gc.BestCD(srcVO);
		
		//3,处理碰撞检测
		//无碰撞直接返回
		if(listObj.length==0){//无碰撞，移动生效
			return;
		}
		//有碰撞
		//-1,贴近到物体
		nestToObj(srcVO);
		
		//-2,如果只有一个物体。则绕行
		//注意，好的情况是绕行之后把速度设置成原来的。
		//现在没有设置成原来的，为的是绕行启动，会和服务器同步一下
		if(listObj.length==1){
			//srcVO._preV.copy(v);//保持原始速度
			detour.Process(srcVO, listObj[0], gc, bound);
			//v.copy(srcVO._preV);//设置回原始速度
		}
		
		dur=getTimer()-startTime;//计算时间
	}
	
	//简单加到指定位置。有障碍物，则停止。这个是npc用的
	public function ProcessSimpleMove4(srcVO:SpacialVO ):Boolean{
		
		//0，计算一下col.row,有用
		gc.fillColAndRow(srcVO);
		
		//没移动最好了
		var v:Vector3D =srcVO.v3d_v;
		var p:Vector3D =srcVO.v3d_p;
		if(v.x==0&&v.z==0){
			return false;
		}
		
		
		
		//1，先尝试加到指定位置
		p.add(v);
		
		//2,执行碰撞检测
		if(gc.isCollide(srcVO)){//出了边界或者撞了障碍物
			p.sub(v);
			return true;
		}
		return false;
	}
	
	//返回的时是否撞上了障碍物.撞上了则返回true
	public function ProcessShotFly(srcVO:SpacialVO):Boolean{
		//没移动最好了
		var a:Vector3D=srcVO.v3d_a;
		var v:Vector3D=srcVO.v3d_v;
		var p:Vector3D=srcVO.v3d_p;
		
		v.add(a);
		
		if(v.x==0&&v.z==0){
			return false;
		}
		
		//0，计算一下col.row,有用
		gc.fillColAndRow(srcVO);
		
		//1，先尝试把速度加到指定
		p.add(v);
		
		//2,碰撞检测
		var isHit:Boolean=gc.FastCD(srcVO);
		
		if(isHit){
			//放到合适位置
			// 1,设置碰撞前的位置和速度
			p.sub(v);
			// 慢速飞行
			v.div(MapManager.FIND_HITPOINT_STEPCOUNT);// !!问题出在了这里！
			// 2,用循环迭代，4次，来找到一个合适碰撞点
			for (var i:int = 0; i < MapManager.FIND_HITPOINT_STEPCOUNT; i++) {

				p.add(v);

				if (gc.FastCD(srcVO)) {
					p.sub(v);
					// T.p("在第"+i+"的时候找到了碰撞点");
					break;
				}
			}
		}
		
		return isHit;
	}
	
	//到了边界，贴到边界
	private function nestToBound(srcVO:SpacialVO ):void{
		var p:Vector3D =srcVO.v3d_p;
		var A2:int=srcVO.aabb.A/2;
		var B2:int=srcVO.aabb.B/2;
		
		var lb:int=bound.left+A2;
		var rb:int=bound.right-A2;
		var tb:int=bound.up-B2;
		var bb:int=bound.down+B2;
		if(p.x<lb){
			p.x=lb;
		}else if(p.x>rb){
			p.x=rb;
		}
		
		if(p.z>tb){
			p.z=tb;
		}else if(p.z<bb){
			p.z=bb;
		}
	}
	
	//贴近到物体
	private function nestToObj(srcVO:SpacialVO ):void{
		var A2:int=srcVO.aabb.A/2;
		var B2:int=srcVO.aabb.B/2;
		var p:Vector3D =srcVO.v3d_p;
		var v:Vector3D =srcVO.v3d_v;
		
//		if(v.x<0){//向左
//			p.x=gc.resultBound.right+A2;
//		}else if(v.x>0){//向右
//			p.x=gc.resultBound.left-A2;
//		}
//		
//		if(v.z>0){//向上
//			p.z=gc.resultBound.down-B2;
//		}else if(v.z<0){//向下
//			p.z=gc.resultBound.up+B2;
//		}
		
		if(v.x!=0){
			if(p.x<gc.resultBound.x){//向左
				p.x=gc.resultBound.left-A2-1;
			}else if(p.x>gc.resultBound.x){//向右
				p.x=gc.resultBound.right+A2+1;
			}
		}
		
		if(v.z!=0){
			if(p.z>gc.resultBound.z){//向上
				p.z=gc.resultBound.up+B2+1;
			}else if(p.z<gc.resultBound.z){//向下
				p.z=gc.resultBound.down-B2-1;
			}
		}
	}
	
	//======================工具函数=================
	public  static function calcX( col:int , CellSize:int):int  {
		return col * CellSize + CellSize / 2;
	}

	public static function calcZ( row:int , CellSize:int):int  {
		return -(row * CellSize + CellSize / 2);
	}

	public  static function calcCol( x:int, CellSize:int):int  {
		return Math.floor(x / CellSize);
	}
	
	//注意这个负号，因为z已经是负数了，所以-z得到的是一个正数
	public static function calcRow( z:int , CellSize:int):int  {
		return Math.floor(-z / CellSize);
	}
	
	//水平方向算角度,前提是x0!=x1
	public static function calcDir(srcX:int,srcZ:int,aimX:int,aimZ:int):int{
		if(aimX<srcX){
			return 270;
		}else if(aimX>srcX){
			return 90;
		}else if(aimZ<srcZ){
			return 180;
		}else if(aimZ>srcZ){
			return 0;
		}
		return 0;
	}
}//end of class
}
